package com.uxsino.simo.collector.connections;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.uxsino.simo.connections.AbstractConnection;
import com.uxsino.simo.connections.exception.SimoConnectionException;
import com.uxsino.simo.connections.exception.SimoQueryException;
import com.uxsino.simo.connections.target.TongWebTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.*;
import javax.management.openmbean.*;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.*;

public class TongWebConnection extends AbstractConnection<TongWebTarget> {

    private static Logger logger = LoggerFactory.getLogger(TongWebConnection.class);

    private MBeanServerConnection mBeanServerConnection;

    private JMXConnector jmxConnector;

    private static List<String> memoryList = Arrays.asList(new String[] { "init", "committed", "max","used" });

    @Override
    public int connect(TongWebTarget target) {
        super.connect(target);
        logger.info("start connecting to TongWebTarget");
        this.target = target;
        connected = false;
        state = 0;
        JMXServiceURL jmxUrl;
        StringBuffer sb = new StringBuffer();
        String[] credentials = new String[]{target.getUsername(), target.getPassword()};
        Map<String, String[]> access = new HashMap<String, String[]>();
        access.put("jmx.remote.credentials", credentials);
        sb.append("service:jmx:rmi:///jndi/rmi://" + target.host + ":" + target.port + "/jmxrmi");
        try {
            jmxUrl = new JMXServiceURL(sb.toString());
            jmxConnector = JMXConnectorFactory.connect(jmxUrl, access);
            jmxConnector.getConnectionId();
            mBeanServerConnection = jmxConnector.getMBeanServerConnection();
            connected = true;
            state = 1;
        } catch (MalformedURLException e) {
            e.printStackTrace();
            logger.error("MalformedURLException exception");
            state = 0;
            connected = false;
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("connection ID cannot be obtained,connection is broken");
            state = 0;
            connected = false;
        }
        return state;
    }

    @Override
    public Object execCmd(Object cmdPattern) throws SimoQueryException, SimoConnectionException {
        String cmd = (String) cmdPattern;
        return  resultTypeObject(cmd);
    }

    @Override
    public Object buildCmd(String cmdPattern, Map<String, String> args) throws SimoQueryException {
        return cmdPattern;
    }

    @Override
    public int close() {
        if (mBeanServerConnection != null) {
            try {
                jmxConnector.close();
            } catch (IOException e) {
                logger.error("error close jmx connector: ", e);
                connected = false;
            }
            mBeanServerConnection = null;
            connected = false;
        }
        super.close();
        return 0;
    }

    private JSONArray resultTypeArray(String cmd) {

        JSONArray result =  new JSONArray();
        String[] cmdArrays = cmd.split("\\|");
        /*Arrays.asList(cmdArrays).stream().filter(temp -> !temp.equals(cmdArrays[0]))
                .forEach(temp -> mBeanServerConnection.getAttribute(new ObjectName(cmdArrays[0]), temp));*/
        ObjectName objectName = null;
        try {
            objectName = new ObjectName(cmdArrays[0]);
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        }
        for (int i= 1;i < cmdArrays.length; i++) {
            try {
                JSONObject o = new JSONObject();
                o.put(cmdArrays[i],mBeanServerConnection.getAttribute(objectName, cmdArrays[i]));
                result.add(o);
            } catch (MBeanException e) {
                e.printStackTrace();
            } catch (AttributeNotFoundException e) {
                e.printStackTrace();
            } catch (InstanceNotFoundException e) {
                e.printStackTrace();
            } catch (ReflectionException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    private JSONObject resultTypeObject(String cmd) {

        JSONObject result =  new JSONObject();
        String[] cmdArrays = cmd.split("\\|");
        ObjectName objectName = null;
        try {
            objectName = new ObjectName(cmdArrays[0]);
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        }

        for (int i= 1;i < cmdArrays.length; i++) {
            try {
                if (cmdArrays[i].equals("HeapMemoryUsage")||cmdArrays[i].equals("NonHeapMemoryUsage")||cmdArrays[i].equals("Usage")) {
                    CompositeDataSupport data = (CompositeDataSupport) mBeanServerConnection.getAttribute(objectName, cmdArrays[i]);
                    for (String memoryType : memoryList) {
                        result.put(memoryType, data.get(memoryType));
                    }
                }
                if(cmdArrays[i].equals("MemoryPoolNames")){
                    String[] matrix = (String[]) mBeanServerConnection.getAttribute(objectName, cmdArrays[i]);
                    StringBuffer sb = new StringBuffer();
                    for (String s : matrix) {
                        sb.append(s+",");
                    }
                    String resultStr=sb.toString().trim();
                    if (resultStr.length()>0){
                        resultStr=resultStr.substring(0,resultStr.length()-1);
                    }
                    result.put(cmdArrays[i],resultStr);
                }else{
                    result.put(cmdArrays[i],mBeanServerConnection.getAttribute(objectName, cmdArrays[i]));
                }
            } catch (MBeanException e) {
                e.printStackTrace();
            } catch (AttributeNotFoundException e) {
                e.printStackTrace();
            } catch (InstanceNotFoundException e) {
                e.printStackTrace();
            } catch (ReflectionException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }


    @Override
    public boolean testWithConnected(String cmdString, String resStart) {
        if (jmxConnector == null) {
            logger.error("连接测试 jmxConnector ：{}", target);
            connected = false;
        } else {
            connected = true;
        }
        return connected;
    }

    @Override
    public boolean connectAndTest(TongWebTarget target, String cmdString, String resStart) {
        boolean result = false;
        try {
            connect(target);
            result = testWithConnected(cmdString, resStart);
        } catch (Exception e) {
            logger.warn("close connection error : {}", e);
        } finally {
            close();
        }
        return result;
    }

}
